/*
    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#pragma once

#include "../NTree.h"
#include "BoxTests.h"


template <class VecType>
class GeomHelpers
{
public:
	static VecType
	shiftDown(const VecType& v, const Exponent expo)
	{
		VecType vOut;
		for(unsigned int iDim=0; iDim<VecType::dimension; iDim++)
			vOut[iDim]=v.getComponent(iDim)>>expo;

		return vOut;
	}

	static Area<VecType>
	getPivot(const Box<VecType>& box)
	{
		VecType vOut;
		unsigned int expo=AuxMath::log2((box.max-box.min).maxComponent() + 1);

		for(unsigned int iDim=0; iDim<VecType::dimension; iDim++)
		{
			const int max=box.max.getComponent(iDim);
			const int min=box.min.getComponent(iDim);

			if(max<=0)
				vOut[iDim]=min>>expo;
			if(min>=0)
				vOut[iDim]=max>>expo;
			if(min<=0 && max >= 0)
				vOut[iDim]=0;
		}
		return Area<VecType>(expo, vOut);
	}

	static void
	getAreas(Area<VecType> aAreas[VecType::childCount], const Box<VecType>& box)
	{
		Area<VecType> pivot=getPivot(box);
		VecType vPivot=pivot.toBox().min;

		for(unsigned int i=0; i<VecType::childCount; i++)
		{
			unsigned int areaExpo=AuxMath::log2(1 +
					(BoxTests<VecType>::getBoxVertex(box, i) - vPivot).maxComponent());
			VecType vOffset= VecType(0).positiveNeighbor(i) - VecType(1);
			aAreas[i].expo = areaExpo;
			aAreas[i].pos = shiftDown(vPivot, areaExpo) + vOffset;
		}
	}

	//clip two sets of areas
	//areas in one set must not contain other areas of that same set
	static void
	intersectAreas(Area<VecType> outAreas[VecType::childCount*2],
			unsigned int &nOutAreas,
			const Area<VecType> inAreas1[VecType::childCount],
			const Area<VecType> inAreas2[VecType::childCount])
	{
		//compare areas to each other
		nOutAreas=0;
		for(unsigned int iDim=0; iDim<VecType::childCount; iDim++)
			for(unsigned int iDim2=0; iDim2<VecType::childCount; iDim2++)
			{
				if(inAreas1[iDim].contains(inAreas2[iDim2]))
				{
					outAreas[nOutAreas++]=inAreas2[iDim2];
					continue;
				}
				if(inAreas2[iDim2].contains(inAreas1[iDim]))
					outAreas[nOutAreas++]=inAreas1[iDim];
			}
	}

};
